package net.simflow.swf.analyzer.stringtrans;

import java.util.ArrayList;
import java.util.Map.Entry;
import java.util.TreeSet;

import net.simflow.swf.analyzer.data.StringConstant;
import net.simflow.swf.analyzer.data.TupleStrInt;
import net.simflow.swf.analyzer.network.data.Flow;
import net.simflow.swf.analyzer.network.data.Link;
import net.simflow.swf.analyzer.network.data.Node;
import net.simflow.swf.analyzer.network.data.Service;
import net.simflow.swf.analyzer.network.stats.data.NetworkStats;

public class NetworkStatsStringGenerator {
	private static final int MAX_LENGTH = 10;

	private static NetworkStatsStringGenerator instance = new NetworkStatsStringGenerator();

	private NetworkStatsStringGenerator() {
	}

	public static NetworkStatsStringGenerator getInstance() {
		return instance;
	}

	public ArrayList<TupleStrInt> generate(String style, NetworkStats nstats) {
		switch (style) {
		case NetworkStats.NAME:
			return this.getNameString(nstats);
		case NetworkStats.FLOW:
			return this.getFlowSetString(nstats);
		case NetworkStats.NODE:
			return this.getNodeSetString(nstats);
		case NetworkStats.SERVICE:
			return this.getServiceSetString(nstats);
		case NetworkStats.LINK:
			return this.getLinkSetString(nstats);
		case NetworkStats.DEGREE_DISTRIBUTION:
			return this.getDegreeDistributionString(nstats);
		}
		return null;
	}

	public ArrayList<TupleStrInt> generate(String style, NetworkStats nstats,
			Flow flow) {
		switch (style) {
		case NetworkStats.NAME:
			return this.getNameString(flow);
		case NetworkStats.FLOW:
			return this.getFlowSetString(flow);
		case NetworkStats.NODE:
			return this.getNodeSetString(flow);
		case NetworkStats.SERVICE:
			return this.getServiceSetString(flow);
		case NetworkStats.LINK:
			return this.getLinkSetString(flow);
		}
		return null;
	}

	private ArrayList<TupleStrInt> getNameString(NetworkStats nstats) {
		if (nstats.getNetworkName() == null) {
			return null;
		}

		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();
		info.add(new TupleStrInt(NetworkStats.NAME, StringConstant.TITLE));
		info.add(new TupleStrInt(nstats.getNetworkName(),
				StringConstant.CONTENT));
		return info;
	}

	private ArrayList<TupleStrInt> getNameString(Flow flow) {
		if (flow == null) {
			return null;
		}

		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();
		info.add(new TupleStrInt(NetworkStats.NAME, StringConstant.TITLE));
		info.add(new TupleStrInt(flow.getNameInNetwork(),
				StringConstant.CONTENT));
		return info;
	}

	private ArrayList<TupleStrInt> getFlowSetString(NetworkStats nstats) {
		if (nstats.getFlowSet() == null) {
			return null;
		}

		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();

		TreeSet<String> set = new TreeSet<String>();
		for (Flow flow : nstats.getFlowSet()) {
			set.add(flow.getNameInNetwork());
		}
		set.comparator();

		for (String str : set) {
			info.add(new TupleStrInt(str, StringConstant.CONTENT));
		}

		if (info.isEmpty()) {
			return null;
		}

		info.add(
				0,
				new TupleStrInt(NetworkStats.FLOW + ": "
						+ nstats.getFlowCount(), StringConstant.TITLE));
		return info;
	}

	private ArrayList<TupleStrInt> getFlowSetString(Flow flow) {
		if (flow == null) {
			return null;
		}

		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();

		info.add(new TupleStrInt(NetworkStats.FLOW, StringConstant.TITLE));
		info.add(new TupleStrInt(flow.getNameInNetwork(),
				StringConstant.CONTENT));
		return info;
	}

	private ArrayList<TupleStrInt> getNodeSetString(NetworkStats nstats) {
		if (nstats.getNodeSet() == null) {
			return null;
		}

		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();

		TreeSet<String> set = new TreeSet<String>();
		for (Node node : nstats.getNodeSet()) {
			set.add(node.getNameInNetwork());
		}
		set.comparator();

		for (String str : set) {
			info.add(new TupleStrInt(str, StringConstant.CONTENT));
		}

		if (info.isEmpty()) {
			return null;
		}

		info.add(
				0,
				new TupleStrInt(NetworkStats.NODE + ": "
						+ nstats.getNodeCount(), StringConstant.TITLE));
		return info;
	}

	private ArrayList<TupleStrInt> getNodeSetString(Flow flow) {
		if (flow == null) {
			return null;
		}

		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();

		TreeSet<String> set = new TreeSet<String>();
		for (Node node : flow.getNodeSet()) {
			set.add(node.getNameInNetwork());
		}
		set.comparator();

		for (String str : set) {
			info.add(new TupleStrInt(str, StringConstant.CONTENT));
		}

		if (info.isEmpty()) {
			return null;
		}

		info.add(0, new TupleStrInt(NetworkStats.NODE + ": "
				+ flow.getNodeSet().size(), StringConstant.TITLE));
		return info;
	}

	private ArrayList<TupleStrInt> getServiceSetString(NetworkStats nstats) {
		if (nstats.getServiceSet() == null) {
			return null;
		}

		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();

		TreeSet<String> set = new TreeSet<String>();
		for (Service service : nstats.getServiceSet()) {
			set.add(service.getNameInNetwork());
		}
		set.comparator();

		for (String str : set) {
			info.add(new TupleStrInt(str, StringConstant.CONTENT));
		}

		if (info.isEmpty()) {
			return null;
		}

		info.add(
				0,
				new TupleStrInt(NetworkStats.SERVICE + ": "
						+ nstats.getServiceCount(), StringConstant.TITLE));
		return info;
	}

	private ArrayList<TupleStrInt> getServiceSetString(Flow flow) {
		if (flow == null) {
			return null;
		}

		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();

		TreeSet<String> set = new TreeSet<String>();
		for (Service service : flow.getServiceSet()) {
			set.add(service.getNameInNetwork());
		}
		set.comparator();

		for (String str : set) {
			info.add(new TupleStrInt(str, StringConstant.CONTENT));
		}

		if (info.isEmpty()) {
			return null;
		}

		info.add(0, new TupleStrInt(NetworkStats.SERVICE + ": "
				+ flow.getServiceSet().size(), StringConstant.TITLE));
		return info;
	}

	private ArrayList<TupleStrInt> getLinkSetString(NetworkStats nstats) {
		if (nstats.getLinkSet() == null) {
			return null;
		}

		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();

		TreeSet<String> set = new TreeSet<String>();
		for (Link link : nstats.getLinkSet()) {
			set.add(link.getShortInfo());
		}
		set.comparator();

		for (String str : set) {
			info.add(new TupleStrInt(str, StringConstant.CONTENT));
		}

		if (info.isEmpty()) {
			return null;
		}

		info.add(
				0,
				new TupleStrInt(NetworkStats.LINK + ": "
						+ nstats.getLinkCount(), StringConstant.TITLE));
		return info;
	}

	private ArrayList<TupleStrInt> getLinkSetString(Flow flow) {
		if (flow == null) {
			return null;
		}

		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();

		TreeSet<String> set = new TreeSet<String>();
		for (Node n : flow.getNodeSet()) {
			for (Node c : n.getChildControlSet()) {
				Link l = new Link(n, c, true);
				set.add(l.getShortInfo());
			}
			for (Node c : n.getChildDataSet()) {
				Link l = new Link(n, c, false);
				set.add(l.getShortInfo());
			}
		}
		set.comparator();

		for (String str : set) {
			info.add(new TupleStrInt(str, StringConstant.CONTENT));
		}

		if (info.isEmpty()) {
			return null;
		}

		info.add(0, new TupleStrInt(NetworkStats.LINK + ": " + set.size(),
				StringConstant.TITLE));
		return info;
	}

	private ArrayList<TupleStrInt> getDegreeDistributionString(
			NetworkStats nstats) {
		if (nstats.getDegreeDistribution() == null) {
			return null;
		}
		nstats.getDegreeDistribution().comparator();

		ArrayList<TupleStrInt> info = new ArrayList<TupleStrInt>();
		for (Entry<Integer, ArrayList<Node>> en : nstats
				.getDegreeDistribution().descendingMap().entrySet()) {
			TreeSet<String> set = new TreeSet<String>();
			for (Node node : en.getValue()) {
				set.add(node.getNameInNetwork());
				if (set.size() >= MAX_LENGTH) {
					break;
				}
			}
			set.comparator();

			StringBuffer str = new StringBuffer();
			str.append(en.getKey());
			str.append(" (").append(en.getValue().size()).append("): ");
			for (String s : set) {
				str.append(" ").append(s).append(";");
			}
			if (set.size() >= MAX_LENGTH && en.getValue().size() > MAX_LENGTH) {
				str.append("...");
			}

			info.add(new TupleStrInt(str.toString(), StringConstant.CONTENT));
		}

		if (info.isEmpty()) {
			return null;
		}

		info.add(0, new TupleStrInt(NetworkStats.DEGREE_DISTRIBUTION,
				StringConstant.TITLE));
		return info;
	}
}
